﻿using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Text;
using System.Windows.Forms;

namespace Server
{
    public partial class MainForm : Form
    {
        private TcpServer server;
        private List<TcpConnection> clients = new List<TcpConnection>();

        public MainForm()
        {
            InitializeComponent();
            TraceTextBox.TextChanged += TraceTextBox_TextChanged;
            Trace.Listeners.Add(new TextBoxTraceListener(TraceTextBox));    // 将TtraceTextBox添加到TraceListener
            AddressListComBox_DropDown(null, null); // 刷新本地IP地址下拉列表
            ClientComboBox_DropDown(null,null); // 刷新客户端地址下拉列表
            AddressListComBox.SelectedIndex = AddressListComBox.Items.Count - 1;    // 本地IP地址列表
            PortTextBox.Text = TcpServer.GetFreePort().ToString();  // 随机空闲端口
        }

        /// <summary>
        /// 文本框更新事件，用于将光标移动到最后一行
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void TraceTextBox_TextChanged(object sender, EventArgs e)
        {
            TraceTextBox.Select(TraceTextBox.TextLength, 0);//光标定位到文本最后
            TraceTextBox.ScrollToCaret();//滚动到光标处
        }

        /// <summary>
        /// 下拉列表下拉事件，用于刷新本地IP列表
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void AddressListComBox_DropDown(object sender, EventArgs e)
        {
            AddressListComBox.Items.Clear();
            AddressListComBox.Items.AddRange(TcpServer.GetLocalAddress());
        }

        /// <summary>
        /// 启动/停止按钮事件，用于启动/停止服务器
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void StartCheckButton_CheckedChanged(object sender, EventArgs e)
        {
            AddressListComBox.Enabled = !StartCheckButton.Checked;
            PortTextBox.Enabled = !StartCheckButton.Checked;
            if (StartCheckButton.Checked)
            {
                server = new TcpServer(AddressListComBox.Text, int.Parse(PortTextBox.Text));
                server.Start(ClientAction); // 启动服务器
                StartCheckButton.Text = "已启动";
                Trace.TraceInformation("server {0} start", server.LocalEndPoint);
            }
            else
            {
                server.Stop(); // 关闭服务器
                clients.ForEach(client => client.Close()); // 关闭所有客户端
                clients.Clear();
                StartCheckButton.Text = "已停止";
                Trace.TraceInformation("server {0} stop", server.LocalEndPoint);
            }
        }

        /// <summary>
        /// 客户端事件处理方法，用于处理客户端的各种事件
        /// </summary>
        /// <param name="connection"></param>
        private void ClientAction(TcpConnection connection)
        {
            /// 客户端连接事件
            connection.OnAccept = client =>
            {
                /// 禁止nagle算法，小数据包频繁发送不粘包,
                /// 但不能彻底解决Tcp的粘包问题，因为Tcp是流协议，
                /// 分包要通过应用层协议去解决。
                client.NoDelay = true;
                clients.Add(client);
                Trace.TraceInformation("client {0} accept", client);
            };
            /// 客户端接收事件
            connection.OnReceive = (client, data) =>
            {
                string text = Encoding.UTF8.GetString(data);
                Trace.TraceInformation("client {0} receive:{1}", client, text);
            };
            /// 客户端关闭事件
            connection.OnClose = (client, activeExit) =>
            {
                if (activeExit) // 客户端主动关闭
                    clients.Remove(connection);
                Trace.TraceInformation("client {0} close:by {1}", client, activeExit ? "itself" : "server");
                Invoke(new Action(()=> ClientComboBox_DropDown(null, null))); // 刷新客户端地址下拉列表
            };
            /// 客户端异常事件
            connection.OnError = (client, ex) =>
            {
                Trace.TraceError("client {0} error:{1}\r\n{2}", client, ex.Message, ex.StackTrace);
            };
        }

        /// <summary>
        /// 发送按钮事件，用于向客户端发送数据
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void SendButton_Click(object sender, EventArgs e)
        {
            if (ClientComboBox.Text == "0.0.0.0:0")
                clients.ForEach(client =>
                {
                    client.Send(SendTextBox.Text);
                    Trace.TraceInformation("server {0} send to client {1}:{2}", server, client, SendTextBox.Text);
                });
            else
            {
                TcpConnection client = ClientComboBox.SelectedItem as TcpConnection;
                client.Send(SendTextBox.Text);
                Trace.TraceInformation("server {0} send to client {1}:{2}", server, client, SendTextBox.Text);
            }
        }

        /// <summary>
        /// 断开按钮事件，用于断开客户端连接
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void CloseButton_Click(object sender, EventArgs e)
        {
            try
            {
                if (ClientComboBox.Text == "0.0.0.0:0")
                    clients.ForEach(c => c.Close());
                else
                {
                    TcpConnection client = ClientComboBox.SelectedItem as TcpConnection;
                    client.Close();
                    clients.Remove(client);
                }
            }
            catch (Exception ex)
            {
                Trace.TraceError(ex.Message);
                Trace.TraceError(ex.StackTrace);
            }
        }

        /// <summary>
        /// 客户端下拉列表下拉事件
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void ClientComboBox_DropDown(object sender, EventArgs e)
        {
            ClientComboBox.DataSource = null;
            ClientComboBox.DataSource = clients;
            ClientComboBox.Text = "0.0.0.0:0";
        }

        /// <summary>
        /// 清除发送窗口
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void ClearSend_Click(object sender, EventArgs e)
        {
            SendTextBox.ResetText();
        }

        /// <summary>
        /// 清除调试窗口
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void ClearTrace_Click(object sender, EventArgs e)
        {
            TraceTextBox.ResetText();
        }
    }
}
